package com.zynn.service.module.es.service;

import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.zynn.common.pojo.dto.user.UserAttentionRelationDTO;
import com.zynn.common.pojo.dto.user.UserDataDTO;
import com.zynn.common.pojo.result.Result;
import com.zynn.service.module.es.bo.DegOneFrientWithWeight;
import com.zynn.service.module.es.bo.GroupBO;
import com.zynn.service.module.es.dao.UsersMapper;
import com.zynn.service.module.es.entity.UserFriend;
import com.zynn.service.module.es.entity.Users;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author admin
 *
 *
 * 初始化用户的好友列表
 *
 */
@Slf4j
@Service
public class InitUserFriendsService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private UsersService usersService;

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private UserFriendService userFriendService;

    /**
     * 权重分数5分
     */
    private static final int SCORE5 = 5;
    /**
     * 权重分数3分
     */
    private static final int SCORE3 = 3;
    /**
     * 权重分数1分
     */
    private static final int SCORE1 = 1;

    /**
     * 计算所有用户的好友
     *
     * @param current
     * @param isAsc
     */
    public void initUserFriends(Integer current, boolean isAsc) {
        if (current == null) {
            current = 1;
        }
        int size = 1000;
        while (true) {
            log.info("一度好友-------------------" + Thread.currentThread().getName() + ",current:" + current);
            Page<Users> page = usersService.selectPage(new Page<>(current, size, "userid", isAsc));
            List<Users> userList = page.getRecords();
            syncUserListWithWeight(userList);

            if (userList.size() < size) {
                log.info("一度好友结束-------------------" + userList.size());
                break;
            }
            current = current + 1;
        }
    }

    /**
     * 计算一个用户的好友
     *
     * @param userId
     */
    public void initUserFriends(Long userId) {
        List<Long> friends = new LinkedList<>();
        Users users = usersService.selectById(userId);
        Integer uFromUserID = users.getUFromUserID();
        if (uFromUserID != null && uFromUserID != 0) {
            friends.add(uFromUserID.longValue());
        }
        findDegOneFriendByGroupMember(userId, friends);
        if (!CollectionUtils.isEmpty(friends)) {
            syncDegOneFriends(userId, friends, null);
        }
    }

    /**
     * 计算一个用户的好友
     *
     * @param userId 用户ID
     */
    public void initUserFriendsWithWeight(Long userId) {
        Map<Long, DegOneFrientWithWeight> userIdToDegOneFriendWithWeightMap = new HashMap<>(100);
        log.info("查询{}邀请或被邀请的人", userId);
        Set<Long> inviteFriends = new HashSet<>();
        List<UserFriend> userFriends = userFriendService.selectList(new EntityWrapper<UserFriend>().eq("invite_user_id", userId).or().eq("accept_user_id", userId));
        if(!CollectionUtils.isEmpty(userFriends)) {
            for (UserFriend userFriend : userFriends) {
                if(!userId.equals(userFriend.getInviteUserId().longValue())) {
                    inviteFriends.add(userFriend.getInviteUserId().longValue());
                }
                if(!userId.equals(userFriend.getAcceptUserId().longValue())) {
                    inviteFriends.add(userFriend.getAcceptUserId().longValue());
                }
            }
        }
        if(!CollectionUtils.isEmpty(inviteFriends)) {
            for (Long inviteFriendId : inviteFriends) {
                addScore(inviteFriendId, SCORE5, userIdToDegOneFriendWithWeightMap);
            }
        }

        log.info("查询{}共同相册的人", userId);
        List<Long> groupMemberFriends = new LinkedList<>();
        findDegOneFriendByGroupMember(userId, groupMemberFriends);
        if(!CollectionUtils.isEmpty(groupMemberFriends)) {
            for (Long groupMemberFriend : groupMemberFriends) {
                addScore(groupMemberFriend, SCORE3, userIdToDegOneFriendWithWeightMap);
            }
        }

        log.info("查询{}关注和被关注的人", userId);

        // update  李琦
        List<UserAttentionRelationDTO> attentionUserList = userFriendService.findUserAttentionOnlyIdList(userId);
        List<UserAttentionRelationDTO> beAttentionUserList = userFriendService.findUserBeAttentionOnlyIdList(userId);
        // -----

        Set<Long> attentionUserSet = new HashSet();
        Set<Long> beAttentionUserSet = new HashSet();
        if(!CollectionUtils.isEmpty(attentionUserList)) {
            for (UserAttentionRelationDTO userAttentionRelationDTO : attentionUserList) {
                attentionUserSet.add(userAttentionRelationDTO.getBeAttentionUserId());
            }
        }
        if(!CollectionUtils.isEmpty(beAttentionUserList)) {
            for (UserAttentionRelationDTO userAttentionRelationDTO : beAttentionUserList) {
                beAttentionUserSet.add(userAttentionRelationDTO.getAttentionUserId());
            }
        }
        for (Long friendUserId : userIdToDegOneFriendWithWeightMap.keySet()) {
            if(attentionUserSet.contains(friendUserId) && beAttentionUserSet.contains(friendUserId)) {
                addScore(friendUserId, SCORE5, userIdToDegOneFriendWithWeightMap);
            } else if(attentionUserSet.contains(friendUserId) || beAttentionUserSet.contains(friendUserId)) {
                addScore(friendUserId, SCORE3, userIdToDegOneFriendWithWeightMap);
            }
        }
        log.info("批量查询用户信息");
        Set<Long> allUserIdSet = new HashSet<>();
        allUserIdSet.add(userId);
        allUserIdSet.addAll(userIdToDegOneFriendWithWeightMap.keySet());

        // update 李琦
        List<UserDataDTO> userDataList = userFriendService.getUserDataByIds(StringUtils.join(allUserIdSet, ","));
        // ---

        Map<Long, UserDataDTO> userIdToUserDataMap = userDataList.stream().collect(Collectors.toMap(UserDataDTO::getUserId, userData -> userData, (oldValue, newValue)-> newValue));
        UserDataDTO userDataDTO = userIdToUserDataMap.get(userId) == null ? new UserDataDTO() : userIdToUserDataMap.get(userId);
        for (Long friendUserId : userIdToDegOneFriendWithWeightMap.keySet()) {
            UserDataDTO friendDataDTO = userIdToUserDataMap.get(friendUserId)!=null?userIdToUserDataMap.get(friendUserId):new UserDataDTO();
            if(friendDataDTO.getSchoolId()!=null && friendDataDTO.getSchoolId().equals(userDataDTO.getSchoolId())) {
                addScore(friendUserId, SCORE5, userIdToDegOneFriendWithWeightMap);
            }
            if(friendDataDTO.getBirthday()!=null && userDataDTO.getBirthday()!=null) {
                long diff = friendDataDTO.getBirthday().getTime() - userDataDTO.getBirthday().getTime();
                long days = diff / (1000 * 60 * 60 * 24);
                if(days>=-3*365 && days<=3*365) {
                    addScore(friendUserId, SCORE5, userIdToDegOneFriendWithWeightMap);
                }
            }
            if(friendDataDTO.getConstellationId()!=null && friendDataDTO.getConstellationId().equals(userDataDTO.getConstellationId())) {
                addScore(friendUserId, SCORE3, userIdToDegOneFriendWithWeightMap);
            }
            if(friendDataDTO.getProfessionId()!=null && friendDataDTO.getProfessionId().equals(userDataDTO.getProfessionId())) {
                addScore(friendUserId, SCORE3, userIdToDegOneFriendWithWeightMap);
            }
        }
        List<String> friendWithWeight = new LinkedList<>();
        for (Map.Entry<Long, DegOneFrientWithWeight> longDegOneFriendWithWeightEntry : userIdToDegOneFriendWithWeightMap.entrySet()) {
            friendWithWeight.add(longDegOneFriendWithWeightEntry.getValue().getWeight() + "|" + longDegOneFriendWithWeightEntry.getValue().getUserId());
        }
        syncDegOneFriends(userId, null, friendWithWeight);
    }

    /**
     * 权重加分
     * @param userId
     * @param score
     * @param userIdToDegOneFriendWithWeightMap
     */
    private void addScore(Long userId, int score, Map<Long, DegOneFrientWithWeight> userIdToDegOneFriendWithWeightMap) {
        if(userIdToDegOneFriendWithWeightMap.containsKey(userId)) {
            DegOneFrientWithWeight degOneFrientWithWeight = userIdToDegOneFriendWithWeightMap.get(userId);
            degOneFrientWithWeight.setWeight(degOneFrientWithWeight.getWeight() + score);
        } else {
            DegOneFrientWithWeight degOneFrientWithWeight = new DegOneFrientWithWeight(userId,score);
            userIdToDegOneFriendWithWeightMap.put(userId, degOneFrientWithWeight);
        }
    }

    private void syncUserList(List<Users> userList) {
        for (Users users : userList) {
            long userId = users.getUserid().longValue();
            Integer uFromUserID = users.getUFromUserID();
            List<Long> friends = new LinkedList<>();
            if (uFromUserID != null && uFromUserID != 0) {
                friends.add(uFromUserID.longValue());
            }
            syncOneUser(userId, users.getUnickname(), users.getUsex(), users.getUpic());
            findDegOneFriendByGroupMember(userId, friends);
            if (!CollectionUtils.isEmpty(friends)) {
                syncDegOneFriends(userId, friends, null);
            }
        }
    }

    private void syncUserListWithWeight(List<Users> userList) {
        for (Users users : userList) {
            long userId = users.getUserid().longValue();
            syncOneUser(userId, users.getUnickname(), users.getUsex(), users.getUpic());
            initUserFriendsWithWeight(userId);
        }
    }

    private void findDegOneFriendByGroupMember(long userId, List<Long> friends) {
        List<GroupBO> joinedGroupList = usersMapper.queryJoinedGroup(userId);
        List<Long> groupIds = new LinkedList<>();
        if (!CollectionUtils.isEmpty(joinedGroupList)) {
            for (GroupBO groupBO : joinedGroupList) {
                groupIds.add(groupBO.getGroupId());
            }
            List<GroupBO> degOneFriends = usersMapper.batchQueryByGroupId(groupIds, userId);
            if (!CollectionUtils.isEmpty(degOneFriends)) {
                for (GroupBO degOneFriend : degOneFriends) {
                    friends.add(degOneFriend.getUserId());
                }
            }
        }
    }

    public void syncOneUser(Long userId, String nickName, int sex, String headPic) {
        Map<String, Object> jsonMap = new HashMap<>(20);
        jsonMap.put("user_id", userId);
        jsonMap.put("nick_name", nickName);
        jsonMap.put("sex", sex);
        jsonMap.put("head_pic", headPic);

        //Map会自动转换为JSON格式的文档源
        IndexRequest indexRequest = new IndexRequest("user_index", "_doc", userId.toString())
                .source(jsonMap);
        IndexResponse indexResponse = null;
        try {
            indexResponse = client.index(indexRequest);
            log.info(indexResponse.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void syncDegOneFriends(Long userId, List<Long> userIdList, List<String> friendWithWeight) {
        if(RecommandUtil.existsIndex(userId,client)){
            this.updateUserFriendIndex(userId,userIdList,friendWithWeight);
        }else{
            this.createUserFriendIndex(userId,userIdList,friendWithWeight);
        }
    }

    private void createUserFriendIndex(Long userId, List<Long> userIdList, List<String> friendWithWeight){
        Map<String, Object> jsonMap = new HashMap<>(20);
        jsonMap.put("user_id", userId);
        jsonMap.put("deg_one_frient", userIdList);
        jsonMap.put("deg_one_friend_with_weight", friendWithWeight);

        //Map会自动转换为JSON格式的文档源
        IndexRequest indexRequest = new IndexRequest("user_friend_index", "_doc", userId.toString())
                .source(jsonMap);
        IndexResponse indexResponse = null;
        try {
            indexResponse = client.index(indexRequest);
            log.info(indexResponse.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void updateUserFriendIndex(Long userId, List<Long> userIdList, List<String> friendWithWeight){
        Map<String, Object> jsonMap = new HashMap<>(20);
        jsonMap.put("deg_one_friend_with_weight", friendWithWeight);

        //Map会自动转换为JSON格式的文档源
        UpdateRequest indexRequest = new UpdateRequest("user_friend_index", "_doc", userId.toString())
                .doc(jsonMap);
        UpdateResponse indexResponse = null;
        try {
            indexResponse = client.update(indexRequest);
            log.info(indexResponse.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void init(Long start, Long end, boolean isAsc) {
        if (start == null) {
            start = 0L;
        }
        if (end == null) {
            end = Long.MAX_VALUE;
        }
        int size = 1000;
        while (true) {
            List<Users> userList = usersService.selectList(
                    Condition.create()
                            .le("userid", end)
                            .ge("userid", start)
                            .orderBy("userid", isAsc)
                            .last("limit " + size)
            );
            syncUserList(userList);

            if (userList.size() < size) {
                log.info("用户结束-------------------" + userList.size());
                break;
            }

            if (isAsc) {
                start = userList.get(size - 1).getUserid().longValue();
            } else {
                end = userList.get(size - 1).getUserid().longValue();
            }
            log.info("用户start-------------------{}", start);
            log.info("用户end-------------------{}", end);
        }
    }
}
